#include "plotter.h"
#include "plottersettings.h"
#include<QtGui>
#include<QAction>
#include<QVector>

/**
 * 整个类的写的步骤，先画图，再考虑放大和缩小的事情
 */


Plotter::Plotter(QWidget* parent) : QWidget(parent){

    //初始化一些私有成员变量
    this->isRubberBandShow = false;
    this->currentSettingIndex = 0;
    //会用默认的构造函数构造对象之后填充到容器里面
    //在本程序中不要进行这种操作
    //this->settingsList.resize(10);

    //设置放大和缩小按钮
    this->btnZoomIn = new QToolButton(this);
    btnZoomIn->setIcon(QIcon(":/zoom/zoomin"));
    btnZoomIn->adjustSize();
    this->btnZoomOut = new QToolButton(this);
    btnZoomOut->setIcon(QIcon(":/zoom/zoomout"));
    btnZoomOut->adjustSize();
    adjustZoomBtnPosition();//调整放大按钮和缩小按钮的位置
    connect(btnZoomIn, QToolButton::clicked, this, Plotter::zoomIn);
    connect(btnZoomOut, QToolButton::clicked, this, Plotter::zoomOut);
    this->btnZoomIn->hide();
    this->btnZoomOut->hide();

    pixMap = QPixmap(size());
    pixMap.fill(Qt::white);
    //不能在这里生成QPainter对象，只能在paintEvent()方法里面生成
    //this->painter = new QPainter(this);
}

/**
 * @brief 调整放大和缩小按钮的位置
 */
void Plotter::adjustZoomBtnPosition(){
    int x = this->width() - ((btnZoomIn->width() + 10) * 2 + 10);//zoomIn需要移动的距离
    int y = x + btnZoomIn->width() + 10;//zoomOut需要移动的距离
    btnZoomIn->move(x, 10);
    btnZoomOut->move(y, 10);
}

void Plotter::setPlotterSetttings(PlotterSettings& settings){
    this->settingsList.append(settings);
    refreshPixmap();
}

void Plotter::setData(QMap<int, QVector<QPointF>>& datas){
    this->datas = datas;
}

QSize Plotter::sizeHint() const{
    return QSize(12 * MARGIN, 8 * MARGIN);
}

QSize Plotter::minimumSizeHint() const{

    return QSize(12 * MARGIN, 8 * MARGIN);
}

/**
 * @brief 绘图的事件
 * @param event
 */
void Plotter::paintEvent(QPaintEvent *event){
    //qDebug() << "Plotter::paintEvent(QPaintEvent *event).....";
    QPainter painter(this);//必须在这个方法里面这样生成
    painter.setPen(Qt::black);
    painter.drawPixmap(0, 0, pixMap);

    //绘制鼠标选择框
    if(this->isRubberBandShow){
        painter.setPen(Qt::cyan);
        //qDebug() << "rubberBandRect = " << rubberBandRect;
        painter.drawRect(this->rubberBandRect.normalized());
    }
}

/**
 * @brief 鼠标按下事件
 * @param event
 */
void Plotter::mousePressEvent(QMouseEvent *event){
    //qDebug() << "Plotter::mousePressEvent(QMouseEvent *event)....";
    if(event->button() == Qt::LeftButton){ //点击的是鼠标左键
        qDebug() << "Plotter::mousePressEvent(QMouseEvent *event)....";
        this->isRubberBandShow = true;
        this->setCursor(Qt::CrossCursor);//鼠标变成十字型
        this->rubberBandRect.setTopLeft(event->pos());
        this->rubberBandRect.setBottomRight(event->pos());
    }
}

void Plotter::mouseMoveEvent(QMouseEvent *event){
    //qDebug() << "Plotter::mouseMoveEvent(QMouseEvent *event)....";
    //鼠标移动的时候，不要进行这样的判断,event->button() == Qt::LeftButton
    //因为在鼠标移动的时候，event->button()永远是返回Qt::NoButton
    if(isRubberBandShow){
        this->rubberBandRect.setBottomRight(event->pos());
        this->update();
    }
}

void Plotter::mouseReleaseEvent(QMouseEvent *event){
    if(event->button() == Qt::LeftButton && isRubberBandShow){
        this->isRubberBandShow = false;
        this->setCursor(Qt::ArrowCursor);

        //将选择框的图上坐标换算成逻辑坐标
        PlotterSettings settings = this->settingsList.at(this->currentSettingIndex);
        double rateX = settings.spanX() / (this->width() - 2 * MARGIN);
        double rateY = settings.spanY() / (this->height() - 2 * MARGIN);
        double left = (rubberBandRect.left() - MARGIN) * rateX + settings.minX;
        double right = left + rubberBandRect.width() * rateX;
        double top = settings.maxY - ((rubberBandRect.top() - MARGIN) * rateY);
        double bottom = top - rubberBandRect.height() * rateY;
        PlotterSettings settings_1;
        settings_1.minX = left;
        settings_1.maxX = right;
        settings_1.minY = bottom;
        settings_1.maxY = top;
        settings_1.toString();
        this->settingsList.insert(currentSettingIndex + 1, settings_1);//注意这里的处理，不要用append
        this->zoomIn();//放大操作
    }

}


/**
 * @brief 部件的大小变化的时候会回调
 * @param event
 */
void Plotter::resizeEvent(QResizeEvent *event){
    qDebug() << "Plotter::resizeEvent(QResizeEvent *event)" ;
    adjustZoomBtnPosition();
    refreshPixmap();
}

/**
 * @brief 放大
 */
void Plotter::zoomIn(){
    qDebug() << "Plotter::zoomIn()......";
    if(currentSettingIndex + 1 < settingsList.size()){
        ++currentSettingIndex;
        refreshPixmap();
        this->btnZoomOut->setEnabled(true);
        this->btnZoomOut->show();
    }else{ //不能再放大了
        this->btnZoomIn->setEnabled(false);
    }
}

/**
 * @brief 缩小
 */
void Plotter::zoomOut(){
    qDebug() << "Plotter::zoomOut().....";
    if(currentSettingIndex - 1 >= 0){
        --currentSettingIndex;
        refreshPixmap();
        this->btnZoomIn->setEnabled(true);
        this->btnZoomIn->show();
    }else{ //不能再缩小了
        this->btnZoomOut->setEnabled(false);
    }
}

void Plotter::refreshPixmap(){
    pixMap = QPixmap(this->size());//将pixmap的大小和部件的大小设置的相同
    pixMap.fill(Qt::white);
    //代表画到pixmap上面，而不是直接画到部件上面
    QPainter painter(&pixMap);
    if(this->settingsList.size() == 0){
        qDebug() << "settingsList.size() == 0";
        return;
    }
    PlotterSettings settings = this->settingsList.at(this->currentSettingIndex);
    settings.adjust();//画图之前都要调整坐标
    drawGrid(painter, pixMap, settings);//绘制网格
    drawCurve(painter, pixMap, settings);//绘制波形
    this->update();
}

/**
 * @brief 绘制网格
 * @param painter
 */
void Plotter::drawGrid(QPainter& painter, QPixmap& pixmap, PlotterSettings& settings){

    //绘制y轴，也就是一系列的竖线
    painter.setPen(Qt::black);
    double graphSpaceX = (pixmap.width() - 2 * MARGIN) * 1.0 / settings.numXTicks;//图上的单元间隔,x方向
    double logicalSpaceX = settings.spanX() / settings.numXTicks;//逻辑上的单元距离,x方向
    for(int i = 0; i <= settings.numXTicks; i++){
        painter.drawLine(MARGIN + i * graphSpaceX, MARGIN, MARGIN + i * graphSpaceX, pixmap.height() - MARGIN);
        QString text =  QString::number(settings.minX + i * logicalSpaceX);
        painter.drawText(MARGIN + i * graphSpaceX - 3, pixmap.height() - MARGIN + 20, text);
    }

    //绘制x轴，也就是一系列的横线
    double graphSpaceY = (pixmap.height() - 2 * MARGIN) * 1.0 / settings.numYTicks;//图上的单元间隔,y方向
    double logicalSpaceY = settings.spanY() / settings.numYTicks;//逻辑上的单元距离,y方向
    for(int i = 0; i <= settings.numYTicks; i++){
        painter.drawLine(MARGIN, MARGIN + i * graphSpaceY, pixmap.width() - MARGIN, MARGIN + i * graphSpaceY);
        QString text = QString::number(settings.maxY - i * logicalSpaceY);
        painter.drawText(MARGIN - 20, MARGIN + i * graphSpaceY, text);
    }

}

/**
 * @brief 绘制波形
 * @param painter
 */
void Plotter::drawCurve(QPainter& painter, QPixmap& pixmap, PlotterSettings& settings){
    qDebug() << "Plotter::drawCurve(QPainter& painter)";
    typedef QMap<int, QVector<QPointF>>::iterator It;
    for(It it = datas.begin(); it != datas.end(); ++it){
        //qDebug() << "it.key() = " << it.key();
        //qDebug() << "it.value()[1] = " << it.value()[1];
        double rateX = (pixmap.width() - 2 * MARGIN) * 1.0 / settings.spanX();
        double rateY = (pixmap.height() - 2 * MARGIN) * 1.0 / settings.spanY();
        bool isFirst = true;
        QPainterPath path;
        for(int j = 0; j < it.value().size(); j++){
            //将逻辑坐标转换成图上坐标
            double graphX = (it.value()[j].x() - settings.minX) * rateX + MARGIN;
            //因为0在下面,所以换算过程和x轴是不一样的
            double graphY = (settings.maxY - it.value()[j].y()) * rateY + MARGIN;
            //只有在绘图范围内才添加进去
            if(graphX >= MARGIN && graphX <= pixmap.width() - MARGIN &&
                    graphY >= MARGIN && graphY <= pixmap.height() - MARGIN){
                if(isFirst){
                    isFirst = false;
                    path.moveTo(graphX, graphY);
                }else{
                    path.lineTo(graphX, graphY);
                }
            }
        }
        QPen pen(Qt::green);
        pen.setStyle(Qt::SolidLine);
        painter.setPen(pen);
        painter.drawPath(path);

    }
}




















